package async_op

import (
	"math/rand"
	"sync"
)

// 工人数组
var workerArray = [maxWorkerCount]*worker{}

// 初始化工人用的锁
var initWorkerLocker = &sync.Mutex{}

// Process 处理异步操作
// bindId = 绑定线程 Id
// asyncOp = 异步操作函数
// continueWith = 继续执行过程, 将在主线程中调用
func Process(bindId BindId, asyncOp func(), continueWith func()) {
	if nil == asyncOp {
		return
	}

	// 根据绑定 Id 获取当前工人
	currWorker := getCurrWorker(bindId)

	if nil != currWorker {
		currWorker.process(asyncOp, continueWith)
	}
}

// 根据绑定 Id 获取当前工人
// bindId = 绑定线程 Id, 将和 len(workerArray) 做取余运算
func getCurrWorker(bindId BindId) *worker {
	if bindId < 0 {
		bindId = -bindId
	}

	workerIndex := bindId.ToInt() % len(workerArray)
	currWorker := workerArray[workerIndex]

	if nil != currWorker {
		return currWorker
	}

	// 加锁
	initWorkerLocker.Lock()
	defer initWorkerLocker.Unlock()

	// 获取当前工人
	currWorker = workerArray[workerIndex]

	// 二次判断
	if nil != currWorker {
		return currWorker
	}

	// 创建一个新的工人
	currWorker = &worker{
		taskQ:   make(chan func(), workerTaskQSize),
		started: 0,
	}

	// 保存到工人数组
	workerArray[workerIndex] = currWorker

	return currWorker
}

// ProcessByRandomBindId 根据随机的 bindId 处理异步操作
// asyncOp = 异步操作函数
// continueWith = 继续执行过程, 将在主线程中调用
func ProcessByRandomBindId(asyncOp func(), continueWith func()) {
	if nil == asyncOp {
		return
	}

	bindId := BindId(rand.Intn(len(workerArray)))
	Process(bindId, asyncOp, continueWith)
}
